/*
 * @Author: CanEve
 * @Date: 2023-07-20 02:47:12
 * @LastEditTime: 2023-07-20 09:33:04
 * @FilePath: /oled/eve_oled.c
 * @Description: copy from internet
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include "eve_oled.h"
#include "fonts.h"
// #include "i2c.h"

#define SH1107_ADDR 0x3c
#define OLED_CMD 0	// 写命令
#define OLED_DATA 1 // 写数据

int fd = 0;
int key_fd=0,usr_led_fd=0;

/**
 * \brief I2C读数据
 *
 * \param[in] fd：I2C设备文件描述符
 * \param[in] dev_addr：I2C设备地址
 * \param[in] reg_addr：寄存器地址
 * \param[in] data：指向希望写入的数据地址
 * \param[in] len：希望写入的字节个数
 *
 * \retval 成功返回0，失败返回-1
 */
int i2c_init(unsigned char *dev_path)
{
	int fd = 0;

	// 打开IIC总线设备节点
	fd = open(dev_path, O_RDWR);

	return fd;
}
/**
 * \brief I2C读数据
 *
 * \param[in] fd：I2C设备文件描述符
 * \param[in] dev_addr：I2C设备地址
 * \param[in] reg_addr：寄存器地址
 * \param[in] data：指向希望写入的数据地址
 * \param[in] len：希望写入的字节个数
 *
 * \retval 成功返回0，失败返回-1
 *
 * \note 该函数适用于8位从机地址，且寄存器地址只有1个字节的情况
 */
int i2c_write(int fd, unsigned short dev_addr, unsigned char reg_addr, unsigned char *data, unsigned int len)
{
	int ret = -1;
	unsigned char buff[20] = {0};
	buff[0] = reg_addr;
	memcpy(&buff[1], data, len);
	// 写数据是1个msg
	struct i2c_msg msg = {
		.addr = dev_addr,
		.flags = 0,
		.len = len + 1,
		.buf = buff,
	};
	struct i2c_rdwr_ioctl_data rdwr_msg = {
		.msgs = &msg,
		.nmsgs = 1,
	};
	ret = ioctl(fd, I2C_RDWR, &rdwr_msg);
	return ret;
}

/**
 * \brief I2C读数据
 *
 * \param[in] fd：I2C设备文件描述符
 * \param[in] dev_addr：I2C设备地址
 * \param[in] reg_addr：寄存器地址
 * \param[out] data：存放读取到的数据
 * \param[in] len：希望读取的字节个数
 *
 * \retval 成功返回0，失败返回-1
 *
 * \note 该函数适用于8位从机地址，且寄存器地址只有1个字节的情况
 */
int i2c_read(int fd, unsigned short dev_addr, unsigned char reg_addr, unsigned char data, unsigned int len)
{
	int ret = -1;
	// 读数据有2个msg
	struct i2c_msg msg[2] = {
		{
			.addr = dev_addr, // 设备地址
			.flags = 0,		  // 标志，为0表示写数据
			.len = 1,		  // 要写的数据的长度
			.buf = &reg_addr, // 要写的数据的地址
		},
		{
			.addr = dev_addr,  // 设备地址
			.flags = I2C_M_RD, // 标志，I2C_M_RD表示主机向主机读数据
			.len = len,		   // 要读取的数据的长度
			.buf = &data,	   // 读取的数据存放的地址
		},
	};
	struct i2c_rdwr_ioctl_data rdwr_msg = {
		.msgs = msg,
		.nmsgs = 2,
	};
	ret = ioctl(fd, I2C_RDWR, &rdwr_msg);
	return ret;
}
void oled_init(int fd)
{
}
void OLED_WR_Byte(unsigned char dat, unsigned cmd)
{
	if (cmd)
	{
		i2c_write(fd, SH1107_ADDR, 0x40, &dat, 1);
	}
	else
	{
		i2c_write(fd, SH1107_ADDR, 0x0, &dat, 1);
	}
}

// 坐标设置

void OLED_Set_Pos(unsigned char x, unsigned char y)
{
	OLED_WR_Byte(0xb0 + y, OLED_CMD);
	OLED_WR_Byte(((x & 0xf0) >> 4) | 0x10, OLED_CMD);
	OLED_WR_Byte((x & 0x0f), OLED_CMD);
}
// 开启OLED显示
void OLED_Display_On(void)
{
	OLED_WR_Byte(0X8D, OLED_CMD); // SET DCDC命令
	OLED_WR_Byte(0X14, OLED_CMD); // DCDC ON
	OLED_WR_Byte(0XAF, OLED_CMD); // DISPLAY ON
}
// 关闭OLED显示
void OLED_Display_Off(void)
{
	OLED_WR_Byte(0X8D, OLED_CMD); // SET DCDC命令
	OLED_WR_Byte(0X10, OLED_CMD); // DCDC OFF
	OLED_WR_Byte(0XAE, OLED_CMD); // DISPLAY OFF
}
// 清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!
void OLED_Clear(void)
{
	u8 i, n;
	for (i = 0; i < Page_num; i++)
	{
		OLED_WR_Byte(0xb0 + i, OLED_CMD); // 设置页地址（0~7）
		OLED_WR_Byte(0x00, OLED_CMD);	  // 设置显示位置—列低地址
		OLED_WR_Byte(0x10, OLED_CMD);	  // 设置显示位置—列高地址
		for (n = 0; n < X_WIDTH; n++)
			OLED_WR_Byte(0, OLED_DATA);
	} // 更新显示
}
void OLED_On(void)
{
	u8 i, n;
	for (i = 0; i < Page_num; i++)
	{
		OLED_WR_Byte(0xb0 + i, OLED_CMD); // 设置页地址（0~7）
		OLED_WR_Byte(0x00, OLED_CMD);	  // 设置显示位置—列低地址
		OLED_WR_Byte(0x10, OLED_CMD);	  // 设置显示位置—列高地址
		for (n = 0; n < X_WIDTH; n++)
			OLED_WR_Byte(1, OLED_DATA);
	} // 更新显示
}
// 在指定位置显示一个字符,包括部分字符
// x:0~127
// y:0~63
// mode:0,反白显示;1,正常显示
// size:选择字体 16/12
void OLED_ShowChar(u8 x, u8 y, u8 chr, u8 Char_Size)
{
	unsigned char c = 0, i = 0;
	c = chr - ' '; // 得到偏移后的值
	if (x > Max_Column - 1)
	{
		x = 0;
		y = y + 2;
	}
	if (Char_Size == 16)
	{
		OLED_Set_Pos(x, y);
		for (i = 0; i < Page_num; i++)
			OLED_WR_Byte(F8X16s[c * 16 + i], OLED_DATA);
		OLED_Set_Pos(x, y + 1);
		for (i = 0; i < Page_num; i++)
			OLED_WR_Byte(F8X16s[c * 16 + i + 8], OLED_DATA);
	}
	else
	{
		OLED_Set_Pos(x, y);
		for (i = 0; i < 6; i++)
			OLED_WR_Byte(F6x8s[c][i], OLED_DATA);
	}
}
// m^n函数
u32 oled_pow(u8 m, u8 n)
{
	u32 result = 1;
	while (n--)
		result *= m;
	return result;
}
// 显示2个数字
// x,y :起点坐标
// len :数字的位数
// size:字体大小
// mode:模式	0,填充模式;1,叠加模式
// num:数值(0~4294967295);
void OLED_ShowNumber(u8 x, u8 y, u32 num, u8 len, u8 size2)
{
	u8 t, temp;
	u8 enshow = 0;
	for (t = 0; t < len; t++)
	{
		temp = (num / oled_pow(10, len - t - 1)) % 10;
		if (enshow == 0 && t < (len - 1))
		{
			if (temp == 0)
			{
				OLED_ShowChar(x + (size2 / 2) * t, y, ' ', size2);
				continue;
			}
			else
				enshow = 1;
		}
		OLED_ShowChar(x + (size2 / 2) * t, y, temp + '0', size2);
	}
}
// 显示一个字符号串
void OLED_ShowString(u8 x, u8 y, u8 *chr, u8 Char_Size)
{
	while (*chr != '\0')
	{
		OLED_ShowChar(x, y, *chr, Char_Size);
		x += 8;
		if (x > 120)
		{
			x = 0;
			y += 2;
		}
		chr++;
	}
}
// 显示汉字
void OLED_ShowCHinese1(u8 x, u8 y, u8 no)
{
	u8 t, adder = 0;
	OLED_Set_Pos(x, y);
	for (t = 0; t < 16; t++)
	{
		OLED_WR_Byte(Hzk[2 * no][t], OLED_DATA);
		adder += 1;
	}
	OLED_Set_Pos(x, y + 1);
	for (t = 0; t < 16; t++)
	{
		OLED_WR_Byte(Hzk[2 * no + 1][t], OLED_DATA);
		adder += 1;
	}
}
/***********功能描述：显示显示BMP图片128×64起始点坐标(x,y),x的范围0～127，y为页的范围0～7*****************/
void OLED_DrawBMP(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, unsigned char BMP[])
{
	unsigned int j = 0;
	unsigned char x, y;

	if (y1 % 8 == 0)
		y = y1 / 8;
	else
		y = y1 / 8 + 1;
	for (y = y0; y < y1; y++)
	{
		OLED_Set_Pos(x0, y);
		for (x = x0; x < x1; x++)
		{
			OLED_WR_Byte(BMP[j++], OLED_DATA);
		}
	}
}
void OLED_Float(unsigned char X, unsigned char Y, double real, unsigned char N)
{
	unsigned char i_Count = 1;
	unsigned char n[12] = {0};
	long j = 1;
	int real_int = 0;
	double decimal = 0;
	unsigned int real_decimal = 0;
	if (real < 0)
	{
		real_int = (int)(-real);
	}
	else
	{
		real_int = (int)real;
	}
	decimal = real - real_int;
	real_decimal = decimal * 1e4;
	while (real_int / 10 / j != 0)
	{
		j = j * 10;
		i_Count++;
	}
	n[0] = (real_int / 10000) % 10;
	n[1] = (real_int / 1000) % 10;
	n[2] = (real_int / 100) % 10;
	n[3] = (real_int / 10) % 10;
	n[4] = (real_int / 1) % 10;
	n[5] = '.';
	n[6] = (real_decimal / 1000) % 10;
	n[7] = (real_decimal / 100) % 10;
	n[8] = (real_decimal / 10) % 10;
	n[9] = real_decimal % 10;
	n[6 + N] = '\0';
	for (j = 0; j < 10; j++)
		n[j] = n[j] + 16 + 32;
	if (real < 0)
	{
		i_Count += 1;
		n[5 - i_Count] = '-';
	}
	n[5] = '.';
	n[6 + N] = '\0';
	OLED_ShowString(X, Y, &n[5 - i_Count], 16); // 12
}

void OLED_Float2(unsigned char X, unsigned char Y, double real, unsigned char N1, unsigned char N2)
{
	unsigned char i_Count = 1;
	unsigned char n[12] = {0};
	long j = 1;
	unsigned int real_int = 0;
	double decimal = 0;
	unsigned int real_decimal = 0;
	X = X * 8;
	real_int = (int)real;
	// Dis_Num(2,0,real_int,5);
	decimal = real - real_int;
	real_decimal = decimal * 1e4;
	// Dis_Num(2,6,real_decimal,4);
	while (real_int / 10 / j != 0)
	{
		j = j * 10;
		i_Count++;
	}
	n[0] = (real_int / 10000) % 10;
	n[1] = (real_int / 1000) % 10;
	n[2] = (real_int / 100) % 10;
	n[3] = (real_int / 10) % 10;

	n[5] = '.';
	n[6] = (real_decimal / 1000) % 10;
	n[7] = (real_decimal / 100) % 10;
	n[8] = (real_decimal / 10) % 10;
	n[9] = real_decimal % 10;
	n[6 + N2] = '\0';
	for (j = 0; j < 10; j++)
		n[j] = n[j] + 16 + 32;
	n[5] = '.';
	n[6 + N2] = '\0';
	OLED_ShowString(X, Y, &n[5 - N1], 12);
}

void OLED_Num2(unsigned char x, unsigned char y, int number)
{
	unsigned char shi, ge;
	int num = number;
	if (num < 0)
	{
		num = -num;
		shi = num % 100 / 10;
		ge = num % 10;
		OLED_fuhao_write(x, y, 13);
		OLED_Num_write(x + 1, y, shi);
		OLED_Num_write(x + 2, y, ge);
	}
	else
	{

		shi = num % 100 / 10;
		ge = num % 10;
		OLED_fuhao_write(x, y, 11);
		OLED_Num_write(x + 1, y, shi);
		OLED_Num_write(x + 2, y, ge);
	}
}

void OLED_Num3(unsigned char x, unsigned char y, int number)
{
	unsigned char ge, shi, bai;
	int num = number;
	if (num < 0)
	{
		num = -num;
		OLED_fuhao_write(x, y, 13); // 显示-号
		ge = num % 10;
		shi = num / 10 % 10;
		bai = num / 100;
		OLED_Num_write(x + 3, y, ge);
		OLED_Num_write(x + 2, y, shi);
		OLED_Num_write(x + 1, y, bai);
	}
	else
	{
		OLED_fuhao_write(x, y, 11);
		ge = num % 10;
		shi = num / 10 % 10;
		bai = num / 100;
		OLED_Num_write(x + 3, y, ge);
		OLED_Num_write(x + 2, y, shi);
		OLED_Num_write(x + 1, y, bai);
	}
}

void OLED_Num4(unsigned char x, unsigned char y, int number)
{
	unsigned char qian, bai, shi, ge;
	int num = number;
	if (num < 0)
	{
		num = -num;
		OLED_fuhao_write(x, y, 13);
	}
	else
		OLED_fuhao_write(x, y, 11);
	qian = num / 1000;
	bai = num % 1000 / 100;
	shi = num % 100 / 10;
	ge = num % 10;

	OLED_Num_write(x + 1, y, qian);
	OLED_Num_write(x + 2, y, bai);
	OLED_Num_write(x + 3, y, shi);
	OLED_Num_write(x + 4, y, ge);
}

void OLED_Num_write(unsigned char x, unsigned char y, unsigned char asc)
{
	int i = 0;
	OLED_Set_Pos(x * 6, y);
	for (i = 0; i < 6; i++)
	{
		OLED_WR_Byte(F6x8s[asc + 16][i], OLED_DATA);
	}
}
void OLED_fuhao_write(unsigned char x, unsigned char y, unsigned char asc)
{

	int i = 0;
	OLED_Set_Pos(x * 6, y);
	for (i = 0; i < 6; i++)
	{
		OLED_WR_Byte(F6x8s[asc][i], OLED_DATA);
	}
}

void OLED_Num5(unsigned char x, unsigned char y, unsigned int number)
{
	unsigned char wan, qian, bai, shi, ge;
	wan = number / 10000;
	qian = number % 10000 / 1000;
	bai = number % 1000 / 100;
	shi = number % 100 / 10;
	ge = number % 10;
	OLED_Num_write(x, y, wan);

	OLED_Num_write(x + 1, y, qian);
	OLED_Num_write(x + 2, y, bai);
	OLED_Num_write(x + 3, y, shi);
	OLED_Num_write(x + 4, y, ge);
}

void OLED_Init(void)
{
	OLED_WR_Byte(0xAE, OLED_CMD); /*display off*/
	OLED_WR_Byte(0x00, OLED_CMD); /*set lower column address*/
	OLED_WR_Byte(0x10, OLED_CMD); /*set higher column address*/
	OLED_WR_Byte(0x20, OLED_CMD); /* Set Memory addressing mode (0x20/0x21) */
	OLED_WR_Byte(0x81, OLED_CMD); /*contract control*/
	OLED_WR_Byte(0x6f, OLED_CMD); /*b0*/
	OLED_WR_Byte(0xA0, OLED_CMD); /*set segment remap*/
	OLED_WR_Byte(0xC0, OLED_CMD); /*Com scan direction*/
	OLED_WR_Byte(0xA4, OLED_CMD); /*Disable Entire Display On (0xA4/0xA5)*/
	OLED_WR_Byte(0xA6, OLED_CMD); /*normal / reverse*/
	OLED_WR_Byte(0xD5, OLED_CMD); /*set osc division*/
	OLED_WR_Byte(0x91, OLED_CMD);
	OLED_WR_Byte(0xD9, OLED_CMD); /*set pre-charge period*/
	OLED_WR_Byte(0x22, OLED_CMD);
	OLED_WR_Byte(0xdb, OLED_CMD); /*set vcomh*/
	OLED_WR_Byte(0x3f, OLED_CMD);
	OLED_WR_Byte(0xA8, OLED_CMD); /*multiplex ratio*/
	OLED_WR_Byte(0x4F, OLED_CMD); /*duty = 1/80*/
	OLED_WR_Byte(0xD3, OLED_CMD); /*set display offset*/
	OLED_WR_Byte(0x68, OLED_CMD); /*18*/
	OLED_WR_Byte(0xdc, OLED_CMD); /*Set Display Start Line*/
	OLED_WR_Byte(0x00, OLED_CMD);
	OLED_WR_Byte(0xad, OLED_CMD); /*set charge pump enable*/
	OLED_WR_Byte(0x8a, OLED_CMD); /*Set DC-DC enable (a=0:disable; a=1:enable) */
	OLED_WR_Byte(0xAF, OLED_CMD); /*display ON*/
}

void executeCMD(const char *cmd, char *result)
{
    char buf_ps[1024];
    char ps[1024]={0};
    FILE *ptr;

    strcpy(ps, cmd);

    if((ptr=popen(ps, "r"))!=NULL)
    {
        while(fgets(buf_ps, 1024, ptr)!=NULL)
        {
           strcat(result, buf_ps);
           if(strlen(result)>1024)
               break;
        }
        pclose(ptr);
        ptr = NULL;
    }
    else
    {
        printf("popen %s error", ps);
    }
}

/**
 * \brief 测试程序
 */
#if 1
int main(int argc, const char *argv[])
{
	char buf[16] = {0};
	usleep(100000);
	int ret_cmd=0;
	// int ret_cmd = system(" echo 130 >/sys/class/gpio/export");
	// usleep(100000);
	// ret_cmd = system(" echo out >/sys/class/gpio/gpio130/direction");
	// usleep(100000);
	ret_cmd = system(" echo 132 >/sys/class/gpio/export");
	usleep(100000);
	ret_cmd = system(" echo out >/sys/class/gpio/gpio132/direction");
	usleep(100000);
	ret_cmd = system(" echo 1 >/sys/class/gpio/gpio132/value");
	usleep(100000);
	// ret_cmd = system(" echo in >/sys/class/gpio/gpio130/direction");
	usleep(100000);
	char args[20];
	char temp_key[5]={0},temp_led=0;
	// key_fd = open("/sys/class/gpio/gpio130/value", 	O_RDWR);
	
	// ret_cmd=read(key_fd,&temp_key,1);
	// printf("key >>> %c\n",temp_key);
	// while (temp_key[0]!='0'/* condition */)
	// {
	// 	usleep(500000);
	// 	read(key_fd,&temp_key,5);
	// 	printf("key >>> %s\n",temp_key);
	// 	/* code */
	// }
	usr_led_fd=open("/sys/class/gpio/gpio132/value", O_RDWR);
	
	fd = i2c_init("/dev/i2c-0"); // 初始化I2C设备
	if (fd < 0)
	{
		printf("i2c_init failed\n");
		return 0;
	}

	OLED_Init();
	printf("init ok\n");
	OLED_Clear();
	// OLED_Float(0, 2, 345.2, 8);
	// OLED_Float(0, 0, 123.56, 8);
	//OLED_Num2(0,0,114514);
	OLED_ShowString(2,3,"hello",5);
	OLED_ShowString(2,4,"world",5);

	OLED_ShowCHinese1(0,8,14);
	OLED_ShowCHinese1(20,8,15);//y<16
	int count_time=0;
	while(1){
		usleep(500000);
		// if(temp_key=='0'){
		// 	read(key_fd,&temp_led,1);
		// 	usleep(500000);
		// 	if(temp_led=='1'){
		// 		write(usr_led_fd,"0",1);
		// 	}else{
		// 		write(usr_led_fd,"1",1);
		// 	}
		// }
		if(count_time%2==0){
			write(usr_led_fd,"0",strlen("0"));
		}else{
			write(usr_led_fd,"1",strlen("1"));
		}
		
		count_time++;
		OLED_Num5(5,14,count_time);
	}
	// i2c_read(fd, MAX30100_DEV_ADDR, 0x01, buf, 1);
	//  buf[0] = 0xF0;
	//  i2c_write(fd, SH1107_ADDR, 0x01, buf, 1); //向0x01寄存器写入0xF0
	// i2c_read(fd, SH1107_ADDR, 0x01, buf, 1);  //从0x01寄存器读取数据

	return 0;
}
#endif